<?php

declare(strict_types=1);

namespace App\CustHub\Service;

use App\CustHub\Constants\CrowSendingConstants;
use App\CustHub\Constants\RoomInviteLogTypeConstants;
use App\CustHub\Helpers\TagReplacer;
use App\CustHub\Mapper\ChContactMapper;
use App\CustHub\Mapper\ChOpSchemeMapper;
use App\CustHub\Mapper\ChRobotMapper;
use App\CustHub\Mapper\ChRoomInviteActiveRoomMapper;
use App\CustHub\Mapper\ChRoomInviteLogMapper;
use App\CustHub\Mapper\ChRoomMapper;
use App\CustHub\Mapper\ChRoomMemberMapper;
use App\CustHub\Model\ChAddFriendRoom;
use App\CustHub\Model\ChContact;
use App\CustHub\Model\ChCrowdInvite;
use App\CustHub\Model\ChCrowdInviteLog;
use App\CustHub\Model\ChCrowdInviteSubTask;
use App\CustHub\Model\ChRoomInviteActiveRoom;
use App\CustHub\Model\ChRoomInviteSendTask;
use App\Robot\Dto\CommonJobDto;
use App\Robot\Dto\RobotMsgDto;
use App\Robot\Job\CommonJob;
use App\Robot\Service\RobotApiService;
use Carbon\Carbon;
use FriendsOfHyperf\Lock\Exception\LockTimeoutException;
use Hyperf\Coroutine\Coroutine;
use Hyperf\Di\Annotation\Inject;
use Mine\Abstracts\AbstractService;
use function FriendsOfHyperf\Lock\lock;
use function Hyperf\Collection\collect;
use function Hyperf\Collection\data_get;
use function Hyperf\Support\optional;

/**
 * 群邀请
 */
class RoomInviteService extends AbstractService
{

    #[Inject]
    protected ChRobotMapper $robotMapper;

    #[Inject]
    protected ChRoomMapper $roomMapper;

    #[Inject]
    protected ChContactMapper $contactMapper;

    #[Inject]
    protected ChRoomMemberMapper $roomMemberMapper;

    #[Inject]
    protected ChRoomInviteLogMapper $roomInviteLogMapper;

    #[Inject]
    protected ChRoomInviteActiveRoomMapper $inviteActiveRoomMapper;

    #[Inject]
    protected ChOpSchemeMapper $schemeMapper;

    #[Inject]
    protected ActiveAddFriendConfigService $addConfigService;

    protected string $roomNameNumberPrefix = 'room_name_number:';


    public function inviteRoomMember(int $schemeId,int $robotId,array $roomConfig,string $userId,int $type,int $subSchemeId=0,bool $isLastCustom=false): void
    {

        $contactInfo = $this->contactMapper->findByRobotIdAndUserId($robotId,$userId);

        //群成员上限
        $roomMemberLimit = $roomConfig['group_user_count'];
        //群邀请引导语
        $inviteGuideSwitch = $roomConfig['invite_guide_switch'];
        $guideText=[
            [
                'msg_type' => 'crowd',
            ]
        ];
        if($inviteGuideSwitch){
            $guideText = array_merge($guideText,$roomConfig['guide_text']);
        }
        $pull_type = (int)$roomConfig['pull_type'];
        $isSubstitute = (int)$roomConfig['is_substitute'] ?? 0;

        $roomWxidList = $this->getInviteActiveRoomWxids($robotId,$schemeId,$type,(int)$roomMemberLimit,$pull_type,$isSubstitute);

        //已在群聊不触发
        $isSkipTrigger = $roomConfig['is_skip_trigger'] ?? 0;
        if($isSkipTrigger){
            //获取所有用户不在群内的群
            $roomWxidList = $this->roomMemberMapper->model::query()
                ->whereIn('room_wxid',$roomWxidList)
                ->where('user_id','<>',$userId)
                ->groupBy('room_wxid')
                ->pluck('room_wxid')
                ->toArray();
        }
        if(!empty($roomWxidList)){
            $roomLimitTime = 0;
            if($pull_type == 1){
                $roomLimitTime = $roomConfig['limit_time'];
            }

            $not_join_invitation_again = $roomConfig['not_join_invitation_again'] ?? 0;
            $invitation_again_conf = $roomConfig['invitation_again_conf'] ?? [];

            $joined_marketing_again = $roomConfig['joined_marketing_again'] ?? 0;
            $imarketing_again_conf = $roomConfig['imarketing_again_conf'] ?? 0;
            $extraSendData = [
                'not_join_invitation_again' => $not_join_invitation_again,
                'invitation_again_conf' => $invitation_again_conf,
                'joined_marketing_again' => $joined_marketing_again,
                'imarketing_again_conf' => $imarketing_again_conf
            ];

            $i = 0;
            foreach ($roomWxidList as $roomWxid){
                $roomWxid = (string)$roomWxid;
                if($this->roomMemberMapper->checkRoomMemberExist($roomWxid,$userId,0)){
                    continue;
                }
                $msgLimit = 0;
                foreach ($guideText as $guideTextItem){
                    if($guideTextItem['msg_type'] == 'crowd'){
                        $content = [
                            'member_list' => [$userId]
                        ];
                        $toId = $roomWxid;
                    }else{
                        $name = '';
                        if(!empty($contactInfo)){
                            $name = !empty($contactInfo->call_name) ? $contactInfo->call_name : $contactInfo->nickname;
                        }
                        $content = TagReplacer::replaceTags($guideTextItem['content'],[
                            'call_name_nickname' => $name
                        ]);;
                        $toId = $userId;
                    }

                    $extra = data_get($guideTextItem,'extra.limit',[]);
                    //单位  1秒 2分钟
                    $unit = data_get($extra,'unit',1);
                    $limit = data_get($extra,'limit',0);
                    if($unit == 2){
                        $limit = $limit * 60;
                    }
                    $msgLimit = $msgLimit + $limit;
                    if($i > 0){
                        $msgLimit = $msgLimit + $roomLimitTime;
                    }
                    container()->get(LowQueueService::class)->push(new CommonJob(new CommonJobDto(
                        classname: RoomInviteService::class,
                        method: 'sendRoomInvite',
                        data:[
                            'robot_id' => $robotId,
                            'to_id' => $toId,
                            'msg_type' => $guideTextItem['msg_type'],
                            'content' => $content,
                            'scheme_id' => $schemeId,
                            'type' => $type,
                            'user_id' => $userId,
                            'extra' => $extraSendData,
                            'sub_scheme_id'=>$subSchemeId,
                        ]
                    )),$msgLimit);
                }
                $i++;
                if($i > 0){
                    $roomLimitTime += $roomLimitTime;
                }
                //更新主任务表信息
                $this->updateSubTaskCount($type,$schemeId,$subSchemeId,$isLastCustom);
            }
        }else{
            //是否创建群
            $createGroup = $roomConfig['create_group'];
            if($createGroup){
                //自动创建群
                $roomName = $roomConfig['group_name'];
                //群编号
                $roomNameNumber = (int)$roomConfig['group_name_number'];
                $redis = redis();
                $key = $this->roomNameNumberPrefix.$schemeId.':'.$type;
                $beforeRoomNameNumber = $redis->get($key);
                if(!empty($beforeRoomNameNumber) && $beforeRoomNameNumber > $roomNameNumber){
                    $roomNameNumber = $beforeRoomNameNumber;
                }

                $redis->set($key,$roomNameNumber);

                $roomName = $roomName.$roomNameNumber;

                //固定成员
                $fixedMembers = $roomConfig['group_members_data'];
                $memberList = [];
                foreach ($fixedMembers as $item){
                    $memberList = array_merge($memberList,$item['user_ids']);
                }

                //固定企业成员
                if(!empty($roomConfig['employee_user_ids'])){
                    $memberList = array_merge($memberList,$roomConfig['employee_user_ids']);
                }

                $msgLimit = 0;
                foreach ($guideText as $guideTextItem){

                    $extra = data_get($guideTextItem,'extra.limit',[]);
                    //单位  1秒 2分钟
                    $unit = data_get($extra,'unit',1);
                    $limit = data_get($extra,'limit',0);
                    if($unit == 2){
                        $limit = $limit * 60;
                    }
                    $msgLimit = $msgLimit + $limit;

                    if($guideTextItem['msg_type'] == 'crowd'){
                        container()->get(LowQueueService::class)->push(new CommonJob(new CommonJobDto(
                            classname: RoomInviteService::class,
                            method: 'createRoom',
                            data:[
                                'robot_id' => $robotId,
                                'user_id' => $userId,
                                'fixed_members' => $memberList,
                                'room_name' => $roomName,
                                'key' => $key,
                                'scheme_id' => $schemeId,
                                'sub_scheme_id' => $subSchemeId,
                                'type' => $type,
                                'isSingleCustomer' => false
                            ]
                        )),$msgLimit);
                    }else{
                        $content = $guideTextItem['content'];
                        container()->get(LowQueueService::class)->push(new CommonJob(new CommonJobDto(
                            classname: RoomInviteService::class,
                            method: 'sendRoomInvite',
                            data:[
                                'robot_id' => $robotId,
                                'to_id' => $userId,
                                'msg_type' => $guideTextItem['msg_type'],
                                'content' => $content,
                                'sub_scheme_id'=>$subSchemeId,
                                'scheme_id'=>$schemeId,
                                'type' => $type,
                            ]
                        )),$msgLimit);
                    }

                }
            }
            //更新主任务表信息
            $this->updateSubTaskCount($type,$schemeId,$subSchemeId,$isLastCustom);
        }
    }

    private function inviteUserToRoom()
    {

    }


    /**
     * 更新主任务统计信息
     * @param int $type
     * @param int $schemeId
     * @param int $subSchemeId
     * @param bool $isLastCustom
     */
    private function updateSubTaskCount(int $type,int $schemeId,int $subSchemeId=0,bool $isLastCustom=false)
    {
        switch ($type){
            case RoomInviteLogTypeConstants::TYPE_BATCH:
                $scheme=ChCrowdInvite::query()->where('id',$schemeId)->first();
                $scheme->complate_total+=1;
                if($isLastCustom && $scheme->status!=CrowSendingConstants::COMPLETE){
                    $scheme->status=CrowSendingConstants::COMPLETE;
                }
                $scheme->save();
                $subScheme=ChCrowdInviteSubTask::query()->where('id',$subSchemeId)->first();
                $subScheme->success_total+=1;
                $subScheme->complete_total+=1;
                $subScheme->save();
                break;
        }
    }

    /**
     * 插入任务邀请日志
     * @param int $type
     * @param int $schemeId
     * @param int $subSchemeId
     */
    private function insertSubTaskLog(int $type,int $schemeId,int $subSchemeId,string $roomWxid,$contactId,$robotId)
    {
        switch ($type){
            case RoomInviteLogTypeConstants::TYPE_BATCH:
                ChCrowdInviteLog::firstOrCreate(
                    ['sub_id'=>$subSchemeId,'contact_id'=>$contactId,'room_id'=>$roomWxid],
                    ['status'=>1,'room_status'=>1,'robot_id'=>$robotId,'date'=>datetime(time(),"Ymd"),'invite_id'=>$schemeId],
                );
                break;
        }
    }

    /**
     * @param int $robotId
     * @param int $schemeId
     * @param int $type
     * @param int $roomMemberCountLimit
     * @param int $pullType
     * @return array
     */
    public function getInviteActiveRoomWxids(int $robotId,int $schemeId,int $type,int $roomMemberCountLimit,int $pullType,int $isSubstitute): array
    {
        //1-按顺序发送全部群邀请  2-随机发送一个群邀请  3-按顺序发一个群邀请,群满发送下一个
        $params = [
            'robot_id' => $robotId,
            'scheme_id' => $schemeId,
            'scheme_type' => $type,
        ];

        $activeRoomList = $this->inviteActiveRoomMapper->getInviteActiveRoomWxid($params);
        $isFullIds = [];
        $list = [];
        foreach ($activeRoomList as $activeRoom){
            if(empty($activeRoom['room'])){
                $isFullIds[] = $activeRoom->id;
                continue;
            }elseif ($activeRoom['room']['room_member_count'] >= $roomMemberCountLimit){
                $isFullIds[] = $activeRoom['id'];
                continue;
            }
            $list[] = $activeRoom;
        }

        if(!empty($isFullIds)){
            //群已满
            $this->inviteActiveRoomMapper->model::query()
                ->whereIn('id',$isFullIds)
                ->update([
                    'status' => 2
                ]);
        }
        if(empty($list)){
            return [];
        }

        switch ($pullType) {
            case 2:
                return [collect($list)->pluck('room_wxid')->random(1)->first()];
            case 3:
                $activeRoom = collect($list)->first();
                if($isSubstitute){
                    //需要替补
                    $this->inviteActiveRoomMapper->update($activeRoom['id'],[
                        'is_substitute' => 1
                    ]);
                }else{
                    //不需要替补
                    $exists = $this->inviteActiveRoomMapper->checkSubstituteRoomExists($schemeId,$type);
                    if($exists){
                        $this->inviteActiveRoomMapper->model::query()
                            ->where('scheme_id',$schemeId)
                            ->where('scheme_type',$type)
                            ->where('is_substitute',1)
                            ->update([
                                'is_substitute' => 0
                            ]);
                    }
                }
                return [$activeRoom['room_wxid']];
            default:
                return collect($list)->pluck('room_wxid')->toArray();
        }
    }

    /**
     * 处理替补群
     * @param string $roomWxid
     * @return void
     */
    public function processSubstituteRoom(string $roomWxid): void
    {
        $this->inviteActiveRoomMapper->model::query()
            ->select(['id','scheme_id','scheme_type'])
            ->where('room_wxid',$roomWxid)
            ->where('status',2)
            ->where('is_substitute',1)
            ->chunk(100,function ($list){
                foreach ($list as $item){
                    //获取当前方案最大的权重
                    $maxSort = $this->inviteActiveRoomMapper->model::query()
                        ->where('scheme_id',$item['scheme_id'])
                        ->where('scheme_type',$item['scheme_type'])
                        ->max('sort');
                    $this->inviteActiveRoomMapper->update($item['id'],[
                        'status' => 0,
                        'sort' => $maxSort+1
                    ]);
                }
            });
    }

    /**
     * 发送群邀请
     * @param array $data
     * @return void
     */
    public function sendRoomInvite(array $data): void
    {
        $robotId = $data['robot_id'];
        $toId = $data['to_id'];
        $subSchemeId = data_get($data,'sub_scheme_id',0);
        $schemeId = data_get($data,'scheme_id',0);
        $type = data_get($data,'type',0);
        $userId = data_get($data,'user_id',0);

        $robotInfo = $this->robotMapper->findById($robotId);
        if(empty($robotInfo) || $robotInfo['login_status'] != 1){
            return;
        }

        $msgData = new RobotMsgDto();
        $msgData->setMsgType($data['msg_type'])
            ->setContent($data['content'])
            ->setToId($toId)
            ->setServerId($robotInfo['server_id'])
            ->setUuid($robotInfo['uuid']);

        $data['msg_type'] == 'crowd' && $this->insertSubTaskLog($type,$schemeId,$subSchemeId,$toId,$userId,$robotId);

        $rst = make(\App\Robot\Service\RobotMessageService::class, [$msgData])->sendMessage();
        //插入批量群邀请日志
        if($data['msg_type'] == 'crowd' && $rst['status']){

            $extra = $data['extra'];
            $not_join_invitation_again = $extra['not_join_invitation_again'] ?? 0;
            $invitation_again_conf = $extra['invitation_again_conf'] ?? [];

            $baseData = [
                'robot_id' => $robotId,
                'scheme_id' => $data['scheme_id'],
                'scheme_type' => $data['type'],
                'room_wxid' => $toId,
                'user_id' => $data['user_id']
            ];

            $taskData = [];
            if($not_join_invitation_again == 1 && !empty($invitation_again_conf)){
                //首次发送群聊未进群后再次发送群邀请
                foreach ($invitation_again_conf as $item){
                    $day = $item['day'];
                    $hour = $item['hour'];
                    $minute = $item['minute'];

                    $sendTime = Carbon::now()->addDays($day)->addHours($hour)->addMinutes($minute)->timestamp;
                    $content = $item['content'];
                    $taskData[] = array_merge($baseData,[
                        'send_time' => $sendTime,
                        'content' => $content,
                        'created_at' => Carbon::now()->toDateString(),
                    ]);
                }

            }
            $joined_marketing_again = $extra['joined_marketing_again'] ?? 0;
            $imarketing_again_conf = $extra['imarketing_again_conf'] ?? 0;

            if($joined_marketing_again == 1 && !empty($imarketing_again_conf)){
                //客户进群后私聊发送营销消息
                foreach ($imarketing_again_conf as $item){
                    $content = $item['content'];
                    $taskData[] = array_merge($baseData,[
                        'send_time' => 0,
                        'content' => $content,
                        'type' => 1,
                        'created_at' => Carbon::now()->toDateString(),
                        'extra' => [
                            'day' => $item['day'],
                            'hour' => $item['hour'],
                            'minute' => $item['minute']
                        ]
                    ]);
                }
            }

            if(!empty($taskData)){
                ChRoomInviteSendTask::insert($taskData);
            }
        }
    }


    /**
     * 创建群
     * @param array $data
     * @return void
     */
    public function createRoom(array $data): void
    {
        $robotId = $data['robot_id'];
        //固定成员
        $fixedMembers = array_unique($data['fixed_members']);

//        $existsFixedMembers = ChContact::query()
//            ->where('robot_id',$robotId)
//            ->whereIn('user_id',$fixedMembers)
//            ->pluck('user_id')
//            ->toArray();

        //触发用户ID
        $userId = $data['user_id'];
        $fixedMembers[] = $userId;
        $memberList = array_unique($fixedMembers);
        stdout_log()->info('创建群聊成员：'.json_encode($memberList));

        $roomName = $data['room_name'];
        $key = $data['key'] ?? '';
        $schemeId = $data['scheme_id'];
        $subSchemeId = data_get($data,'sub_scheme_id',0);
        $type = $data['type'] ?? RoomInviteLogTypeConstants::TYPE_KEYWORD_SINGLE;

        $isSingleCustomer = $data['isSingleCustomer'] ?? false;

        $lock = lock('single_customer_scheme_lock:'.$userId.':'.$schemeId.':'.$type,4);
        $day = Carbon::now()->toDateString();
        try {
            $lock->block(3);
            logger()->info('创建群聊方案ID：'.$robotId.'__'.$schemeId);
            //检查用户是否已经触发过
            $exists = $this->roomInviteLogMapper->checkUserExists($schemeId,(int)$robotId,$userId,$type);
            if($exists){
                return;
            }

            if($type == RoomInviteLogTypeConstants::TYPE_KEYWORD_SINGLE || $type == RoomInviteLogTypeConstants::TYPE_TAG_SINGLE){
                //当日创建数量
                $dayLimit = $data['day_limit'];
                $dayCreatedQuantity = $this->roomInviteLogMapper->getDayCreatedQuantity($schemeId,$day,$type);
                if($dayCreatedQuantity >= $dayLimit){
                    return;
                }
            }

            $robotInfo = $this->robotMapper->findById($robotId);
            if(empty($robotInfo) || $robotInfo['login_status'] != 1){
                return;
            }

            $robotApiService = make(\App\Common\Robot\Robot::class,[$robotInfo->server_id,$robotInfo->uuid])->gateway();
            $result = $robotApiService->createRoom(array_unique($memberList));
            if($result === false){
                return;
            }

            if(!empty($key)){
                redis()->incr($key);
            }

            Coroutine::sleep(randomFloat(2,3));
            $roomWxid = $result['room_id'];

            //加入群列表
            if ($type == RoomInviteLogTypeConstants::TYPE_GREETING) {
                $config = $this->addConfigService->getOperateConfig(['uid' => $robotInfo->uid]);
                $operateCfg = $config->operate_cfg;
                $drawRoomCfg = data_get($operateCfg, 'draw_group_cfg', []);
                $maxNumber = $drawRoomCfg[0]['max_number'];
                ChAddFriendRoom::insert([
                    'uid' => $robotInfo->uid,
                    'main_uid' => $robotInfo->main_uid,
                    'create_user_id' => $robotInfo->user_id,
                    'room_wxid' => $roomWxid,
                    'status' => 1,
                    'add_number' => 0,
                    'human_ceiling' => $maxNumber,
                    'sort' => 1
                ]);
            }

//            if ($type == RoomInviteLogTypeConstants::TYPE_ROOM_CODE){
//                $roomCodeService = container()->get(ChRoomCodeService::class);
//                $roomCode = $roomCodeService->mapper->findById($schemeId);
//
//                if ($roomCode) {
//
//                    $roomCodeService->addNewCreatedRoom(
//                        $schemeId,
//                        $robotInfo->main_uid,
//                        $roomWxid,
//                    );
//
//                    // 更新群活码的当前房间ID列表
//                    $currentRoomIds = data_get($roomCode, 'room_rule_cfg.current_room_ids', []);
//                    if (!in_array($roomWxid, $currentRoomIds)) {
//                        $currentRoomIds[] = $roomWxid;
//                        $roomCodeService->mapper->update($schemeId, [
//                            'room_rule_cfg->current_room_ids' => $currentRoomIds
//                        ]);
//                    }
//                }
//            }

            //设置群名称
            $robotApiService->editRoomName($roomWxid,$roomName);

            if(!$isSingleCustomer){
                //多客户模式，新创建的群自动加入到生效群列表中
                $maxSort = $this->inviteActiveRoomMapper->model::query()
                    ->where('scheme_id',$schemeId)
                    ->where('scheme_type',$type)
                    ->max('sort');

                $activeRoom = [
                    'scheme_id' => $schemeId,
                    'scheme_type' => $type,
                    'room_wxid' =>$roomWxid,
                    'genders' => json_encode([0,1,2]),
                    'sort' => $maxSort + 1,
                    'created_at' => Carbon::now()->toDateTimeString(),
                    'updated_at' => Carbon::now()->toDateTimeString()
                ];
                ChRoomInviteActiveRoom::insert($activeRoom);
                if($type == RoomInviteLogTypeConstants::TYPE_KEYWORD_MULTI){
                    $schemeInfo = $this->schemeMapper->findById($schemeId);
                    if(!empty($schemeInfo)){
                        $cfg = $schemeInfo->cfg;
                        $room_cnf = $cfg['room_cnf'];
                        $group_pull_data = $room_cnf['group_pull_data'];
                        $new_group_pull_data = [
                            [
                                'sort' => $maxSort + 1,
                                'crowd_id'=> $roomWxid,
                                'genders' => [0,1,2]
                            ]
                        ];
                        $group_pull_data = array_merge($group_pull_data,$new_group_pull_data);
                        $cfg['room_cnf']['group_pull_data'] = $group_pull_data;
                        $this->schemeMapper->update($schemeId,['cfg'=>$cfg]);
                        $this->schemeMapper->deleteCache($schemeId);
                    }
                }
            }

            //插入批量群邀请日志
            $this->insertSubTaskLog($type,$schemeId,$subSchemeId,$roomWxid,$userId,$robotId);
            //记录触发日志
            $logData = [
                'scheme_id' => $schemeId,
                'robot_id' => $robotId,
                'day' => $day,
                'user_id' => $userId,
                'room_wxid' => $roomWxid,
                'type' => $type,
                'created_at' => Carbon::now()->toDateTimeString()
            ];
            $this->roomInviteLogMapper->save($logData);

        } catch (LockTimeoutException $e) {
            // 无法获取锁...
        } catch (\Exception $e) {
            // 无法获取锁...
        }finally {
            optional($lock)->release();
        }
    }

    /**
     * 提取群wxid
     * @param int $robotId
     * @param array $groupPullData
     * @return array
     */
    private function extractRoomWxids(int $robotId,array $groupPullData): array
    {
        return collect($groupPullData)
            ->filter(function ($item) use ($robotId){
                return $item['robot_id'] = $robotId;
            })
            ->sortByDesc(function ($item) {
                // 根据 sort 字段进行降序排序
                return $item['crowd_infos']['sort'];
            })
            ->pluck('crowd_infos.crowd_id','robot_id')
            ->toArray();
    }
}